package org.codehaus.activemq.jndi;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.naming.spi.ObjectFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class JNDIReferenceFactory
  implements ObjectFactory
{
  static Log log = LogFactory.getLog(JNDIReferenceFactory.class);

  public Object getObjectInstance(Object object, Name name, Context nameCtx, Hashtable environment)
    throws Exception
  {
    Object result = null;
    if ((object instanceof Reference)) {
      Reference reference = (Reference)object;

      if (log.isTraceEnabled()) {
        log.trace("Getting instance of " + reference.getClassName());
      }

      Class theClass = loadClass(this, reference.getClassName());
      if (JNDIStorableInterface.class.isAssignableFrom(theClass))
      {
        JNDIStorableInterface store = (JNDIStorableInterface)theClass.newInstance();
        Properties properties = new Properties();
        for (Enumeration iter = reference.getAll(); iter.hasMoreElements(); )
        {
          StringRefAddr addr = (StringRefAddr)iter.nextElement();
          properties.put(addr.getType(), addr.getContent() == null ? "" : addr.getContent());
        }

        store.setProperties(properties);
        result = store;
      }
    }
    else {
      log.error("Object " + object + " is not a reference - cannot load");
      throw new RuntimeException("Object " + object + " is not a reference");
    }
    return result;
  }

  public static Reference createReference(String instanceClassName, JNDIStorableInterface po)
    throws NamingException
  {
    if (log.isTraceEnabled()) {
      log.trace("Creating reference: " + instanceClassName + "," + po);
    }
    Reference result = new Reference(instanceClassName, JNDIReferenceFactory.class.getName(), null);
    try {
      Properties props = po.getProperties();
      for (Enumeration<?> iter = props.propertyNames(); iter.hasMoreElements(); ) {
        String key = (String)iter.nextElement();
        String value = props.getProperty(key);
        StringRefAddr addr = new StringRefAddr(key, value);
        result.add(addr);
      }
    }
    catch (Exception e)
    {
      Properties props;
      Enumeration iter;
      log.error(e.getMessage(), e);
      throw new NamingException(e.getMessage());
    }
    return result;
  }

  public static Class loadClass(Object thisObj, String className)
    throws ClassNotFoundException
  {
    ClassLoader loader = thisObj.getClass().getClassLoader();
    Class theClass;
    if (loader != null) {
      theClass = loader.loadClass(className);
    }
    else
    {
      theClass = Class.forName(className);
    }
    return theClass;
  }
}